Skip to content

Retro Questions

Remember this funnel diagram from earlier, showing the steps in a company's hiring process?

A funnel that starts wide and gets narrow, with 4 levels. “Submitted application”, to “Phone screen”, to “Interviews”, to “Offer”

We haven't talked about the second step yet, the “Phone screen”.

Like all of the steps in the funnel, this step takes many different forms. Sometimes, it's not even done by phone! It can be done by Zoom, or in person, or even asynchronously by email.

The idea with the phone screen is that the company wants to rule out any candidates that are not a good fit, so that they can schedule fewer interviews. They're typically conducted by someone in the HR department, rarely by developers.

The tricky thing here is that the non-technical screener is tasked with trying to evaluate the technical proficiency of the candidate. Typically, the way this works is that the screener has a list of technical trivia questions, along with their accepted answers. They ask the question, and see if you mention some of the words from their answer key.

These questions are often hopelessly out of date. They might've gotten them from their development team years ago. Or maybe they googled "React interview questions" and didn't notice that the post they found is from 2016.

In this course, we focus on modern React. This is generally a good thing, but it does mean that you might not know how to answer phone-screen questions from earlier versions of React.

So, in this lesson, I'm going to share some of the concepts that I've seen in phone screens. You don't need to fully understand these concepts, but hopefully this gives you enough context to pass any phone screens.

What's the difference between “Presentational” and “Container” components?

In 2015, Redux co-creator Dan Abramov wrote a blog post which went viral, Presentational and Container Components.

The blog post suggests a design pattern where components are split into two categories:

  • Presentational components render the UI, based on a set of props.
  • Container components manage the state and business logic for those components.

For example, here's what this pattern might look like:

function Counter({ count, increment }) {
return (
<button onClick={increment}>
Current count: {count}
</button>
);
}
function CounterContainer() {
const [count, setCount] = React.useState(0);
function increment() {
setCount(count + 1);
}
return (
<Counter
count={count}
increment={increment}
/>
);
}
export default CounterContainer;

This is a pretty silly example, since both components are so small, but it shows the pattern. One component is focused purely on the UI, the other component manages the logic and state.

In practice, this pattern was most often used with Redux. The container components would pluck data out of Redux and pass it along to the presentational components.

These days, this pattern isn't used very widely. Even its creator, Dan Abramov, no longer encourages it; instead, he suggests moving complex business logic into custom hooks.

What is a higher-order component?

A higher-order component, often shortened to “HOC”, is a function that takes a component and wraps it in a new internal component. Typically, this is done to share some logic across multiple components.

Here's an example:

function withUser(WrappedComponent) {
return (props) => {
const { data } = useSWR('/api/user', fetcher);
return <WrappedComponent user={data} {...props} />
};
}

The withUser function takes an input component, and produces a way to render that input component with some "locked-in" props.

For example, maybe we have a Dashboard component. We can “lock in” the user like this:

const DashboardWithUser = withUser(Dashboard);
// We then render this element:
<DashboardWithUser />
// And, internally, it'll render:
<Dashboard user={data} />

Then, when other components need the current user, we can re-use this HOC:

const AccountSettingsWithUser = withUser(AccountSettings);
// We then render this element:
<AccountSettingsWithUser colorTheme="dark" />
// And, internally, it'll render:
<AccountSettings user={data} colorTheme="dark" />

If this is hurting your brain, you're not alone; HOCs were one of the most mind-melting parts of React.

Why did anyone do this? HOCs were popular in the days before hooks. Back then, there was no obvious way to share logic between components, and so we had to get creative.

Today, we can solve this problem in a much more straightforward way using custom hooks. I would build a useUser custom hook:

function useUser() {
const { data } = useSWR('/api/user', fetcher);
return data;
}

Name at least 𝑛 lifecycle methods

As we briefly saw in the course, React components used to be defined as JavaScript classes:

class Button extends React.Component {
state = {
count: 0,
};
handleClick = () => {
console.log('Clicked!');
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<button onClick={this.handleClick}>
{this.props.children}
</button>
);
}
}

In addition to the custom methods we'd define on this class, like handleClick in this example, there were also several “lifecycle methods” we could define. React would then call these methods at specific times.

We actually learned about one lifecycle method in the course, componentDidCatch. That method is called when the component throws an error.

Here's another example:

class App extends React.Component {
componentDidMount() {
console.log('Component mounted');
}
render() {
return (
<>
<h1>Hello World</h1>
</>
);
}
}

The componentDidMount lifecycle method is called right after the component mounts.

In a phone screen, I was asked to list at least 5 lifecycle methods. Here are the most common ones:

  • componentDidMount
  • componentWillUpdate (deprecated)
  • componentDidUpdate
  • render
  • componentWillUnmount
  • componentDidCatch

You can view all of the lifecycle methods in the React docs.

What is a render prop?

This is another hacky thing we had to do, before we had hooks!

Here's what the pattern looks like:

function ScrollPosition({ children }) {
const [scrollPosition, setScrollPosition] = React.useState(0);
React.useEffect(() => {
function handleScroll() {
setScrollPosition(window.scrollY);
}
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return children(scrollPosition);
}
function App() {
return (
<ScrollPosition>
{(scrollPosition) => {
return (
<p>
The user has scrolled by {scrollPosition} pixels.
</p>
);
}}
</ScrollPosition>
);
}

The ScrollPosition component takes a single prop, children. Unlike most components, however, children is not a React element; instead, it's a function.

When we render the ScrollPosition component, we invoke that children function with some sort of data. In this case, it's the scrollPosition state variable.

The parent component App then supplies a function via the children prop, and that function is called with the data. We use the data to render a paragraph.

The most common convention for render props is to use the children prop, but we can name the prop whatever we want. Some folks prefer to use the name render:

function ScrollPosition({ render }) {
// ✂️ Everything else the same
return render(scrollPosition);
}
function App() {
return (
<ScrollPosition
render={(scrollPosition) => {
return (
<p>
The user has scrolled by {scrollPosition} pixels.
</p>
);
}}
/>
);
}

Either way, it works the same way.

Like we saw with Higher-Order Components, render props were used because there was no built-in way to share logic between components. And so we would create components like ScrollPosition or WindowDimensions, so that we could re-use these components whenever we needed this data.

These days, custom hooks generally offer a much nicer solution to this problem. I haven't needed to use render props in years.

How does React's synthetic events system work?

So, this is something you might've actually noticed: React has its own custom events system.

Suppose we have the following code:

import React from 'react';
function Counter() {
return (
<button
onClick={(event) => {
console.log('Event', event);
}}
>
Click me
</button>
);
}
export default Counter;

When the user clicks the button, we'll see something like this:

Screenshot of the browser console showing a 'SyntheticBaseEvent'

This is different from what we see when we add a click handler through vanilla JavaScript, with window.addEventListener():

Screenshot of the browser console showing a 'PointerEvent'

This is because React comes with a “synthetic” event system. It's a wrapper around the built-in event system.

Why does React do this? There's two big reasons:

  1. Browser Standardization. In the past, native events were slightly different between browsers. Synthetic events are the same no matter which browser is being used.
  2. Performance. React can bundle multiple event handlers across the application.

Let's dig into that second point. Suppose we had something like:

function App() {
return (
<>
<Counter />
<Counter />
<Counter />
<Counter />
<Counter />
</>
);
}

We're rendering 5 instances of the Counter component, and each one listens for clicks with an onClick method. Rather than registering 5 event listeners with addEventListener, it can instead register a single “real” event listener, and re-use it across all 5 instances.

What are the drawbacks? The biggest drawback is that it significantly increases React's file size.

There are “React-like” tools like Preact and Inferno that offer the same API as React, but with a much smaller file size. One of the ways they accomplish this is by not having a synthetic events system.

Honestly, I'm not sure that React should have a synthetic event system. We don't really need React to do the standardization for us anymore, as browsers have coalesced around a standard event API. And the performance benefits are murky.

Here's a sandbox with the code snippet from above, in case you wanted to explore:

Code Playground

import React from 'react';

window.addEventListener('click', (event) => {
console.log('Real event:', event);
})

function App() {
return (
<button
onClick={(event) => {
console.log('Synthetic event', event);
}}
>
Click me
</button>
);
}

export default App;